package cn.anc.aonicardv.util;

import android.annotation.TargetApi;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.format.Formatter;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Collections;
import java.util.List;

import androidx.annotation.NonNull;


public class WifiHelper {
    /**
     * Wifi Constant
     */
    /*Wifi State*/
    int WIFI_CONNECTING = 0;
    int WIFI_CONNECTED = 1;
    int WIFI_CONNECT_FAILED = 2;
    int WIFI_UNKNOWN_ERROR = -1;

    /*Wifi Type*/
    String KEY_WPA = "WPA_PSK";
    String KEY_NONE = "NONE";

    /*Wifi Error Code*/
    int ERROR_NETWORK_INFO_EMPTY = 61168;
    int ERROR_NETWORK_TYPE_NOT_WIFI = 61169;
    int ERROR_WIFI_INFO_EMPTY = 61170;
    int ERROR_WIFI_PWD_NOT_MATCH = 61171;
    int ERROR_NETWORK_NOT_OPEN = 61172;
    int ERROR_WIFI_IS_CONNECTED = 61173;

    private static final String tag = "WifiHelper";
    private static WifiHelper instance = null;
    private WifiManager mWifiManager;
    private WifiManager.WifiLock wifiLock;

    public static WifiHelper getInstance(Context context) {
        if (null == instance) {
            synchronized (WifiHelper.class){
                if (instance == null) {
                    instance = new WifiHelper(context);
                }
            }
        }
        return instance;
    }

    private WifiHelper(Context c) {
        if (c != null) {
            mWifiManager = (WifiManager) c.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        }
    }



    /**
     * WIFI 是否打开
     *
     */
    public boolean isWifiOpen() {
        return mWifiManager != null && mWifiManager.isWifiEnabled();
    }

    /**
     * 获取当前网络信息
     * @param context  上下文
     * @return  NetworkInfo
     */
    public static NetworkInfo getNetworkInfo(Context context) {
        ConnectivityManager manager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if(manager != null) {
            return manager.getActiveNetworkInfo();
        }
        return null;
    }

    /**
     * 判断Wifi是否连接
     * @param context   上下文
     */
    public static boolean isNetWorkConnectedType(Context context, int type) {
        if (context == null) {
            return false;
        }
        Context mContext = context.getApplicationContext();
        ConnectivityManager connectivity = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity != null) {
            NetworkInfo[] info = connectivity.getAllNetworkInfo();
            if (info != null) {
                for (NetworkInfo anInfo : info) {
                    if (anInfo.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) {
                        return anInfo.getType() == type;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 判断外部网络
     * @param tag   网络标识头
     */
    public boolean isOutSideWifi(String tag){
        WifiInfo info = getWifiConnectionInfo();
        if(info != null){
            String ssid = info.getSSID();
            ssid = formatSSID(ssid);
            return ssid != null && !TextUtils.isEmpty(ssid) && ssid.startsWith(tag);
        }
        return false;
    }

    /**
     * 获取Wifi状态
     * @param context   上下文
     */
    public int getWifiState(Context context) {
        if (context == null) {return WIFI_UNKNOWN_ERROR;}
        NetworkInfo wifiNetworkInfo = getNetworkInfo(context);
        if(wifiNetworkInfo == null) return WIFI_UNKNOWN_ERROR;
        if (wifiNetworkInfo.getDetailedState() == NetworkInfo.DetailedState.OBTAINING_IPADDR
                || wifiNetworkInfo.getDetailedState() == NetworkInfo.DetailedState.CONNECTING) {
            return WIFI_CONNECTING;
        } else if (wifiNetworkInfo.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) {
            return WIFI_CONNECTED;
        } else {
            return WIFI_CONNECT_FAILED;
        }
    }

    /**
     * 截断字符串(以空字符截断)
     * @param s   字符串
     */
    public static String interceptChar0Before(String s) {
        if (s == null) {
            return null;
        }
        char[] chars = s.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char c : chars) {
            Character ch = c;
            if (0 == ch.hashCode()) { //遇到空字符就跳出循环
                break;
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 查看WIFI当前是否处于打开状态
     *
     * @return true 处于打开状态；false 处于非打开状态(包括UnKnow状态)。
     */
    public boolean isWifiClosed() {
        int wifiState = getWifiState();
        return wifiState == WifiManager.WIFI_STATE_DISABLED
                || wifiState == WifiManager.WIFI_STATE_DISABLING;
    }

    /**
     * 查看WIFI当前是否处于关闭状态
     *
     * @return true 处于关闭状态；false 处于非关闭状态(包括UNKNOWN状态)
     */
    public boolean isWifiOpened() {
        int wifiState = getWifiState();
        return wifiState == WifiManager.WIFI_STATE_ENABLED
                || wifiState == WifiManager.WIFI_STATE_ENABLING;
    }

    /**
     * 如果WIFI当前处于关闭状态，则打开WIFI
     */
    public void openWifi() {
        if (mWifiManager != null && isWifiClosed()) {
            mWifiManager.setWifiEnabled(true);
        }
    }

    /**
     * 如果WIFI当前处于打开状态，则关闭WIFI
     */
    public void closeWifi() {
        if (mWifiManager != null && isWifiOpened()) {
            mWifiManager.setWifiEnabled(false);
        }
    }

    /**
     * 获取当前Wifi的状态编码
     *
     * @return WifiManager.WIFI_STATE_ENABLED，WifiManager.WIFI_STATE_ENABLING，
     * WifiManager.WIFI_STATE_DISABLED，WifiManager.WIFI_STATE_DISABLING，
     * WifiManager.WIFI_STATE_UnKnown 中间的一个
     */
    public int getWifiState() {
        if (mWifiManager != null) {
            return mWifiManager.getWifiState();
        }
        return 0;
    }

    /**
     * 获取系统保存的Wifi网络配置列表
     */
    public List<WifiConfiguration> getSavedWifiConfiguration() {
        if(mWifiManager != null){
            return mWifiManager.getConfiguredNetworks();
        }
        return null;
    }

    /**
     * 获取扫描到的网络信息列表
     */
    public List<ScanResult> getWifiScanResult() {
        if(mWifiManager != null){
            return mWifiManager.getScanResults();
        }
        return null;
    }

    /**
     * 执行一次Wifi的扫描
     */
    public synchronized void startScan() {
        if (mWifiManager != null) {
            mWifiManager.startScan();
        }
    }

    /**
     * 通过netWorkId来连接一个已经保存好的Wifi网络
     *
     * @param netWorkId network specific id
     */
    public void connectionConfiguration(int netWorkId) {
        if (mWifiManager != null) {
            mWifiManager.disconnect();
            mWifiManager.enableNetwork(netWorkId, true);
//            mWifiManager.reconnect();
        }
    }

    /**
     * 断开一个指定ID的网络
     */
    public void disconnectionConfiguration(int netWorkId) {
        if (mWifiManager != null) {
            mWifiManager.disableNetwork(netWorkId);
            mWifiManager.disconnect();
        }
    }

    /**
     * 检测尝试连接某个网络时，查看该网络是否已经在保存的队列中间
     *
     * @param netWorkId network specific id
     * @return true : network save in configuration
     */
    private boolean configurationNetWorkIdCheck(int netWorkId) {
        List<WifiConfiguration> wifiConfigurationList = getSavedWifiConfiguration();
        if(null == wifiConfigurationList){
            return false;
        }
        for (WifiConfiguration temp : wifiConfigurationList) {
            if (null != temp && temp.networkId == netWorkId) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取Wifi的信息化
     *
     */
    public WifiInfo getWifiConnectionInfo() {
        return mWifiManager.getConnectionInfo();
    }

    /**
     * 创建一个WifiLock
     */
    public void createWifiLock(String lockName) {
        if (mWifiManager != null) {
            if(TextUtils.isEmpty(lockName)){lockName = "wifiLock";}
            wifiLock = mWifiManager.createWifiLock(lockName);
        }
    }

    /**
     * 锁定WIFI，使得在熄屏状态下，仍然可以使用WIFI
     */
    public void acquireWifiLock() {
        if (wifiLock != null) {
            wifiLock.acquire();
        }else{
            createWifiLock("wifiLock");
            if (wifiLock != null) {
                wifiLock.acquire();
            }
        }
    }

    /**
     * 解锁WIFI
     */
    public void releaseWifiLock() {
        if (wifiLock != null) {
            if (wifiLock.isHeld()) {
                wifiLock.acquire();
            }
        }
    }

    /**
     * 保存一个新的网络
     *
     * @param _wifiConfiguration   网络配置
     */
    public int addNetWork(WifiConfiguration _wifiConfiguration) {
        int netWorkId = -255;
        if (_wifiConfiguration != null && mWifiManager != null) {
            netWorkId = mWifiManager.addNetwork(_wifiConfiguration);
        }
        return netWorkId;
    }

    /**
     * 保存并连接到一个新的网络
     *
     * @param _wifiConfiguration  网络配置
     */
    public void addNetWorkAndConnect(WifiConfiguration _wifiConfiguration) {
        int netWorkId = addNetWork(_wifiConfiguration);
        if (mWifiManager != null && netWorkId != -255) {
            mWifiManager.disconnect();
            mWifiManager.enableNetwork(netWorkId, true);
        }
    }

    /**
     * 获取当前连接状态中的Wifi的信号强度
     * @return  有效值： 0 ~ -100  , 1 : 数据错误
     * 0 ~ -50 : 信号最好
     * -50 ~ -60 ：信号一般
     * -60 ~ -70 ：信号较差
     * -70 ~ -100 : 信号最差
     */
    public int getConnectedWifiLevel() {
        WifiInfo wifiInfo = getWifiConnectionInfo();
        if (wifiInfo != null) {
            String connectedWifiSSID = wifiInfo.getSSID();
            connectedWifiSSID = formatSSID(connectedWifiSSID);
            List<ScanResult> scanResultList = getWifiScanResult();
            if (scanResultList != null) {
                for (ScanResult temp : scanResultList) {
                    if(temp != null){
                        String tempSSID = formatSSID(temp.SSID);
                        if (tempSSID != null && !TextUtils.isEmpty(tempSSID)
                                && tempSSID.equals(connectedWifiSSID)) {
                            return temp.level;
                        }
                    }
                }
            }
        }
        return 1;
    }

    /**
     * 格式化SSID
     * @param ssid  原始SSID
     */
    public static String formatSSID(String ssid){
        if(TextUtils.isEmpty(ssid)) return null;
        if(ssid.contains("\"")){
            ssid = ssid.replace("\"", "");
        }
        if(ssid.contains(" ")){
            ssid = ssid.replace(" ", "");
        }
        return ssid;
    }

    /**
     * 删除一个已经保存的网络
     *
     * @param netWorkId  网络ID
     */
    public void removeNetWork(int netWorkId) {
        if (mWifiManager != null) {
            mWifiManager.removeNetwork(netWorkId);
        }
    }

    /**
     * Wifi加密类型的描述类
     */
    public enum WifiCipherType {
        NONE, IEEE8021XEAP, WEP, WPA, WPA2, WPAWPA2
    }




    /**
     *
     * @param context  上下文
     */
    public static int getNetWorkType(Context context) {
        if (!isNetWorkConnectedType(context, ConnectivityManager.TYPE_WIFI)) {
            return 0;
        }

        ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();
        String type = null;
        if (networkInfo != null) {
            type = networkInfo.getTypeName();
        }
        if (type == null) return 0;
        if (type.equalsIgnoreCase("WIFI")) {
            return 1;
        } else if (type.equalsIgnoreCase("MOBILE")) {
            TelephonyManager telephonyManager = (TelephonyManager) context
                    .getSystemService(Context.TELEPHONY_SERVICE);
            switch (telephonyManager.getNetworkType()) {
                case TelephonyManager.NETWORK_TYPE_EVDO_0:// ~ 400-1000 kbps
                case TelephonyManager.NETWORK_TYPE_EVDO_A:// ~ 600-1400 kbps
                case TelephonyManager.NETWORK_TYPE_HSDPA:// ~ 2-14 Mbps
                case TelephonyManager.NETWORK_TYPE_HSPA:// ~ 700-1700 kbps
                case TelephonyManager.NETWORK_TYPE_HSUPA:// ~ 1-23 Mbps
                case TelephonyManager.NETWORK_TYPE_UMTS: // ~ 400-7000 kbps
                case TelephonyManager.NETWORK_TYPE_EVDO_B:// ~ 5 Mbps
                    return 1;
                case TelephonyManager.NETWORK_TYPE_1xRTT:// ~ 50-100 kbps
                case TelephonyManager.NETWORK_TYPE_CDMA:// ~ 14-64 kbps
                case TelephonyManager.NETWORK_TYPE_EDGE:// ~ 50-100 kbps
                case TelephonyManager.NETWORK_TYPE_GPRS:// ~ 100 kbps
                case TelephonyManager.NETWORK_TYPE_IDEN:// ~25 kbps
                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
                default:
                    return 0;
            }
        }

        return 0;
    }

    /**
     * 枚举网络状态
     * NET_NO：没有网络
     * NET_2G:2g网络
     * NET_3G：3g网络
     * NET_4G：4g网络
     * NET_WIFI：wifi
     * NET_UNKNOWN：未知网络
     */
    public enum NetState {
        NET_NO, NET_2G, NET_3G, NET_4G, NET_WIFI, NET_UNKNOWN
    }

    /**
     * 判断当前网络连接类型
     *
     * @param context 上下文
     * @return 状态码
     */
    public static NetState getConnectedType(Context context) {
        NetState stateCode = NetState.NET_NO;
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo ni = cm.getActiveNetworkInfo();
        if (ni != null && ni.isConnectedOrConnecting()) {
            switch (ni.getType()) {
                case ConnectivityManager.TYPE_WIFI:
                    stateCode = NetState.NET_WIFI;
                    break;
                case ConnectivityManager.TYPE_MOBILE:
                    switch (ni.getSubtype()) {
                        case TelephonyManager.NETWORK_TYPE_GPRS: //联通2g
                        case TelephonyManager.NETWORK_TYPE_CDMA: //电信2g
                        case TelephonyManager.NETWORK_TYPE_EDGE: //移动2g
                        case TelephonyManager.NETWORK_TYPE_1xRTT:
                        case TelephonyManager.NETWORK_TYPE_IDEN: //api<8 : replace by 11


                            break;
                        case TelephonyManager.NETWORK_TYPE_EVDO_A: //电信3g
                        case TelephonyManager.NETWORK_TYPE_UMTS:
                        case TelephonyManager.NETWORK_TYPE_EVDO_0:
                        case TelephonyManager.NETWORK_TYPE_HSDPA:
                        case TelephonyManager.NETWORK_TYPE_HSUPA:
                        case TelephonyManager.NETWORK_TYPE_HSPA:
                        case TelephonyManager.NETWORK_TYPE_EVDO_B: //api<9 : replace by 14
                        case TelephonyManager.NETWORK_TYPE_EHRPD:  //api<11 : replace by 12
                        case TelephonyManager.NETWORK_TYPE_HSPAP:  //api<13 : replace by 15
                            stateCode = NetState.NET_3G;
                            break;
                        case TelephonyManager.NETWORK_TYPE_LTE:   //api<11 : replace by 13
                            stateCode = NetState.NET_4G;
                            break;
                        default:
                            // http://baike.baidu.com/item/TD-SCDMA 中国移动 联通 电信 三种3G制式
                            if (ni.getSubtypeName().equalsIgnoreCase("TD-SCDMA") ||
                                    ni.getSubtypeName().equalsIgnoreCase("WCDMA") ||
                                    ni.getSubtypeName().equalsIgnoreCase("CDMA2000")) {
                                stateCode = NetState.NET_3G;
                            }else{
                                stateCode = NetState.NET_UNKNOWN;
                            }

                    }
                    break;
                default:
                    stateCode = NetState.NET_UNKNOWN;
            }

        }
        return stateCode;
    }

    /**
     * 获取Wifi的Ip
     * @param context   上下文
     */
    public static String getWifiIP(Context context) {
        WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        WifiInfo wifiinfo = wifiManager.getConnectionInfo();
        String ip = formatIpAddress(wifiinfo.getIpAddress());
        if(TextUtils.isEmpty(ip)) return null;
        if (ip.equals("0.0.0.0")) {
            ip = getLocalIpAddress();
            if (ip.equals("0.0.0.0")) {
            }
        }
        return ip;
    }

    /**
     * 获取本地IP地址
     */
    private static String getLocalIpAddress() {
        try {
            String ipv4;
            List<NetworkInterface> nilist = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface ni : nilist) {
                List<InetAddress> ialist = Collections.list(ni.getInetAddresses());
                for (InetAddress address : ialist) {
                    ipv4 = address.getHostAddress();
//                    if (!address.isLoopbackAddress() && InetAddressUtils.isIPv4Address(ipv4)) {
                    if(!address.isLoopbackAddress() && address instanceof Inet4Address) {
                        return ipv4;
                    }
                }
            }
        } catch (SocketException ex) {
            ex.printStackTrace();
        }
        return "0.0.0.0";
    }

    /**
     * 获取当前网关
     * @return 网关IP
     */
    public String getGateWay(Context context) {
        WifiManager wifiService = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        if (wifiService == null) return null;

        DhcpInfo dhcpInfo = wifiService.getDhcpInfo();
        return Formatter.formatIpAddress(dhcpInfo.gateway);
    }

    /**
     * 获取WifiInfo的IP地址
     * @param wifiInfo  WifiInfo对象
     */
    public static String getWifiIP(WifiInfo wifiInfo){
        String ip = null;
        if(wifiInfo != null){
            int ipAddress = wifiInfo.getIpAddress();
            ip = formatIpAddress(ipAddress);
        }
        return ip;
    }

    /**
     * 格式化IP地址
     * @param ipAddress  ip地址
     */
    private static String formatIpAddress(int ipAddress) {
        return (ipAddress & 0xFF) + "." +
                ((ipAddress >> 8) & 0xFF) + "." +
                ((ipAddress >> 16) & 0xFF) + "." +
                (ipAddress >> 24 & 0xFF);
    }


    /**
     * 释放资源
     */
    public void release(){
        instance = null;
        releaseWifiLock();
        mWifiManager = null;
    }

    public static void bindNetwork(Context context) {
        if (Build.VERSION.SDK_INT >= 21) {
            final ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkRequest.Builder builder = new NetworkRequest.Builder();
            builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
            builder.removeTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
            NetworkRequest request = builder.build();
            ConnectivityManager.NetworkCallback callback = new ConnectivityManager.NetworkCallback() {
                @TargetApi(Build.VERSION_CODES.M)
                @Override
                public void onAvailable(@NonNull Network network) {
                    if (connMgr != null) {
                        connMgr.unregisterNetworkCallback(this);
                        if (Build.VERSION.SDK_INT >= 23) {
                            connMgr.bindProcessToNetwork(network);
                        } else {
                            ConnectivityManager.setProcessDefaultNetwork(network);
                        }
                    }
                }
            };

            if (connMgr != null) {
                connMgr.registerNetworkCallback(request, callback);
            }
        }
    }
}
